/*
 * Copyright (c) xxxx-xxxx, Huan
 * SPDX-License-Identifier: Apache-2.0
 *
 * bilibili UID:179895513
 *
 * Date           Author       Notes
 * 2023-04-28     Huan       the first version
 */
#include "board.h"
#include "dcmi_drv.h"

DCMI_HandleTypeDef dcmi;
static DMA_HandleTypeDef  dcmi_dma;

static void rt_hw_dmci_dma_init(void)
{
    __DMA2_CLK_ENABLE();

    dcmi_dma.Instance           = DMA2_Stream1;
    dcmi_dma.Init.Channel       = DMA_CHANNEL_1;
    dcmi_dma.Init.Direction     = DMA_PERIPH_TO_MEMORY;
    dcmi_dma.Init.PeriphInc     = DMA_PINC_DISABLE;
    dcmi_dma.Init.MemInc        = DMA_MINC_ENABLE;
    dcmi_dma.Init.PeriphDataAlignment   = DMA_PDATAALIGN_WORD;
    dcmi_dma.Init.MemDataAlignment      = DMA_MDATAALIGN_WORD;
    dcmi_dma.Init.Mode          = DMA_CIRCULAR;
    dcmi_dma.Init.Priority      = DMA_PRIORITY_HIGH;
    dcmi_dma.Init.FIFOMode      = DMA_FIFOMODE_DISABLE;
    dcmi_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    dcmi_dma.Init.MemBurst      = DMA_MBURST_SINGLE;
    dcmi_dma.Init.PeriphBurst   = DMA_PBURST_SINGLE;

    HAL_DMA_DeInit(&dcmi_dma);
    if (HAL_DMA_Init(&dcmi_dma) != HAL_OK)
    {
        Error_Handler();
    }
    __HAL_LINKDMA(&dcmi, DMA_Handle, dcmi_dma);
    HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0x00, 0);
    HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
}

void HAL_DCMI_MspInit(DCMI_HandleTypeDef* hdcmi)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    if(hdcmi->Instance == DCMI)
    {
        /* Peripheral clock enable */
        __DCMI_CLK_ENABLE();
        __GPIOA_CLK_ENABLE();
        __GPIOB_CLK_ENABLE();
        __GPIOC_CLK_ENABLE();
        __GPIOE_CLK_ENABLE();
        /**DCMI GPIO Configuration
        PA4     ------> DCMI_HSYNC
        PA6     ------> DCMI_PCLK
        PB7     ------> DCMI_VSYNC
        PC6     ------> DCMI_D0
        PC7     ------> DCMI_D1
        PC8     ------> DCMI_D2
        PC9     ------> DCMI_D3
        PC11    ------> DCMI_D4
        PB6     ------> DCMI_D5
        PE5     ------> DCMI_D6
        PE6     ------> DCMI_D7
        */
        GPIO_InitStruct.Pin     = GPIO_PIN_4 | GPIO_PIN_6;
        GPIO_InitStruct.Mode    = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull    = GPIO_PULLUP;
        GPIO_InitStruct.Speed   = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        GPIO_InitStruct.Pin     = GPIO_PIN_6 | GPIO_PIN_7;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        GPIO_InitStruct.Pin     = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_11;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        GPIO_InitStruct.Pin     = GPIO_PIN_5 | GPIO_PIN_6;
        HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

        HAL_NVIC_SetPriority(DCMI_IRQn,0,1);
        HAL_NVIC_EnableIRQ(DCMI_IRQn);
    }
}

static rt_err_t rt_hw_dcmi_init(void)
{
    dcmi.Instance = DCMI;
    dcmi.Init.SynchroMode   = DCMI_SYNCHRO_HARDWARE;
    dcmi.Init.PCKPolarity   = DCMI_PCKPOLARITY_RISING;
    dcmi.Init.VSPolarity    = DCMI_VSPOLARITY_LOW;
    dcmi.Init.HSPolarity    = DCMI_HSPOLARITY_LOW;
    dcmi.Init.CaptureRate   = DCMI_CR_ALL_FRAME;
    dcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
    dcmi.Init.JPEGMode = DCMI_JPEG_ENABLE;
    HAL_DCMI_DeInit(&dcmi);
    if (HAL_DCMI_Init(&dcmi) != HAL_OK)
    {
        rt_kprintf("dcmi init error!");
        return -RT_ERROR;
    }

    __HAL_DCMI_CLEAR_FLAG(&dcmi, DCMI_IT_FRAME|DCMI_IT_OVR|DCMI_IT_ERR|DCMI_IT_VSYNC|DCMI_IT_LINE);
    __HAL_DCMI_ENABLE_IT(&dcmi, DCMI_IT_FRAME);
    __HAL_DCMI_ENABLE(&dcmi);

    rt_hw_dmci_dma_init();

    return RT_EOK;
}

void DCMI_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    HAL_DCMI_IRQHandler(&dcmi);

    /* leave interrupt */
    rt_interrupt_leave();
}

#include "user_test.h"
/* Capture a frame of the image */
void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
    /* enter interrupt */
    rt_interrupt_enter();

    __HAL_DCMI_CLEAR_FLAG(&dcmi, DCMI_FLAG_FRAMERI);

    Test_Handle.jpg_process();

    __HAL_DCMI_ENABLE_IT(&dcmi, DCMI_IT_FRAME);

    /* leave interrupt */
    rt_interrupt_leave();
}
void DMA2_Stream1_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    HAL_DMA_IRQHandler((&dcmi)->DMA_Handle);

    /* leave interrupt */
    rt_interrupt_leave();
}

static int rt_dcmi_init(void)
{
    rt_hw_dcmi_init();

    return RT_EOK;
}


#include "rtdef.h"
INIT_PREV_EXPORT(rt_dcmi_init);
